home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!cs.odu.edu!Amiga-Request
- From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
- Newsgroups: comp.sources.amiga
- Subject: v90i198: ls 4.0k - yet another unix-like ls command, Part04/04
- Message-ID: <13042@xanth.cs.odu.edu>
- Date: 3 Jul 90 19:26:07 GMT
- Sender: tadguy@cs.odu.edu
- Reply-To: kim@uts.amdahl.com (Kim E. DeVaughn)
- Lines: 1546
- Approved: tadguy@cs.odu.edu (Tad Guy)
- X-Mail-Submissions-To: Amiga@cs.odu.edu
- X-Post-Discussions-To: comp.sys.amiga
-
- Submitted-by: kim@uts.amdahl.com (Kim E. DeVaughn)
- Posting-number: Volume 90, Issue 198
- Archive-name: unix/ls-4.0k/part04
-
- #!/bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 4 (of 4)."
- # Contents: src/ls.c.aa
- # Wrapped by tadguy@xanth on Tue Jul 3 15:22:14 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/ls.c.aa' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/ls.c.aa'\"
- else
- echo shar: Extracting \"'src/ls.c.aa'\" \(45212 characters\)
- sed "s/^X//" >'src/ls.c.aa' <<'END_OF_FILE'
- X/* ----------------------------------------------------------------------
- X ls.c - main source code file for the "improved" directory utility.
- X
- Xls v4.0k is (c) Copyright 1990, Kim E. DeVaughn, all rights reserved.
- X
- X
- XFYI:
- X
- X UNIX is a registered trademark of AT&T. They had nothing to do with any
- X of this code, but did provide the "model" for some of its output formats
- X and options.
- X
- X
- XAuthor:
- X
- X Kim E. DeVaughn
- X
- X v4.0k May 11, 1990 Pretty much completely revised the output formats.
- X Much more like UNIX's "ls" in its output, options,
- X etc. Several bugs fixed. Many new options.
- X
- X Justin V. McCormick
- X
- X v3.1 July 29, 1989 Bug fixes, new output width and height options.
- X v3.0 July 25, 1989 Instant sorting, best-fit output, new features.
- X v2.2 December 1988 Fixed status return and multiple wildcard pathnames.
- X v2.1 December 1988 Minor size reduction, fixed a few bugs from 2.0.
- X v2.0 November 1988 Revised for Lattice 5.0 and made 1.3 compatible.
- X v1.0 August 1986 Written from scratch, my first Amiga project.
- X
- X
- XNotice:
- X
- XThis program is copyrighted. See the "License" accompanying this distribution
- Xfor limitations, and other details.
- X
- X
- XSynopsis:
- X
- XFeatures intelligent columnar listing, versatile sort options, UNIX-style
- Xpattern matching, UNIX-like output formats and flags, recursive subdirectory
- Xlisting, and more!
- X
- X
- XUsage:
- X ls [ [ -options <args> ] [ names ] ] ...
- X
- X
- XBugs and Limitations:
- X
- X"ls" cannot pattern match devices (like "dh*:"), since this would involve
- Xanother level of recursion and parsing the Device List. See the README file
- Xfor other limitations, and known bugs.
- X
- X
- XHistory:
- X
- X Changes From 3.1 to 4.0k:
- X
- X o New (default) long listing format that *looks* like UNIX's (except for
- X things like owner, group ID, etc).
- X o Block sizes now include *all* blocks associated with a file, and are
- X finally accurate for FFS devices.
- X o By default, upper/lower case *is* significant in the output listing,
- X and in the wildcard pattern matching.
- X o By default, directories and files are intermixed, according to their
- X alphabetic position.
- X o By default, the short listing format uses fixed width columns, based
- X on the length of the longest filename in the directory. Variable
- X width columns are still available.
- X o By default, "hidden", "*.info", and "dot" files (eg, .foo) are not
- X displayed. There are switches for each, as well as an "all" flag.
- X o Several new options like the ability to limit the "-R" recursion depth;
- X ability to show absolute and relative path names in the long format
- X listing; additional control of directory header and totalization
- X lines; elimination of redundent totalization lines; showing/sorting
- X on files' "disk keys"; control of the date format; sort by date/size
- X defaults to newest/biggest first; and a few other things.
- X o Improved error handling and error msgs. Better "break" handling. No
- X more "memory leaks" (yes, there is one in v3.1 ... it looses 300 bytes
- X on an error exit).
- X o The assignment of option flags has been "rationalized". Applicable
- X flags from the UNIX "ls" were assigned 1st, followed by other flags
- X from v3.1, followed by new flags added in this rev. However ... some
- X flag assignments from previous revs were changed when better mnemonic
- X values could be found, etc. So ... check the usage, and/or docs.
- X Caveat emptor!
- X o Flags requiring arguments (eg, -N) may or may not be seperated from
- X the argument by spaces. So, "-Nfoo" is just as legal as "-N foo".
- X
- X
- X Changes From 3.0 to 3.1:
- X
- X o Fixed random errors from uninitialized argument count in GetCLIArgs().
- X o New -X and -Y options to specify short format columns and rows.
- X
- X
- X Changes From 2.2 to 3.0:
- X
- X o Added many new command line options! See Usage descriptions and docs.
- X o "Instant" output sorting, now using an on-the-fly insertion sort.
- X o New Short listing technique is row-by-row, redirects to PRT: or file.
- X o Better columnization of short listings, uses best-fit optimization.
- X o Formatted output parsing system implemented for long listings.
- X o Improved ^C handling, now breaks immediately in mid-output.
- X o New command line parser, now handles multiple options mixed with names.
- X o Added separate pattern matching for directories and files. [ DOESN'T WORK - KED ]
- X o Now inhibits system requesters from popping up by default.
- X o Added custom cres.o module for more size savings.
- X o Now uses Exec List functions for smaller, faster code.
- X o Fixed random cli_ReturnCode and pr_Result2 value CLI returns.
- X o Rewrote many sections, further code cleaning/commenting.
- X o Eliminated main(), LS handles the _main() function for smaller code.
- X o Compiled with 5.03.90 (beta) Lattice compiler, saved a few bytes.
- X
- X
- X Changes From 2.1 to 2.2:
- X
- X o Fixed erroneous Status returns.
- X o Fixed bug with multiple wildcarded pathnames.
- X o Compiled with LC 5.0 Patch 3 and CAPE 2.0, saved another 46 bytes.
- X o Eliminated an extra stpcpy(), saved another few bytes.
- X
- X
- X Changes From 2.0 to 2.1:
- X
- X o Fixed the show comment feature, a last minute bug in 2.0.
- X o Fixed the "Unknown option ''" message problem.
- X o Optimized the assembly branches, reduced code size another few bytes.
- X
- X
- X Changes From 1.0 to 2.0:
- X
- X o Source code prototyped, linted, traced, optimized, tweaked, etc.
- X o Made resident ("pseudo-pure") by linking with cres.o from LC 5.0.
- X o High-volume routines recoded in assembly (lssup.a).
- X o Now handles multiple paths/files on a command line, up to 30.
- X o New sort flags, including no sort.
- X o Enhanced wildcards, understands complex *.?*.* expressions now.
- X o More efficient ExNext() performance, less ram used for recursion.
- X o SIGBREAKF_CTRL_C signal (Ctrl-C) cleanly aborts at any point now.
- X o Command line parser handles quoted pathnames now (LC 5.0 benefit).
- X o Short listing finally auto-adjusts to new console window sizes!
- X o Pen color escape codes bypassed when redirecting long output.
- X o Sorting by size or date is also subsorted alphabetically now.
- X o Long listing shows new 1.3 file attributes, plus comment indicator.
- X o File dates are now in international format, YY-MM-DD.
- X o Fixed listings with files datestamped after 99-12-31 (overflow).
- X o Fixed listings with files datestamped before 78-01-01 (time < 0).
- X -------------------------------------------------------------------- */
- X
- X/* ---------------------- LS SOURCE ---------------------------------- */
- X
- X#include "ls.h"
- X
- X/* Extern CODE from lssup.a */
- Xextern BYTE *aindex __ARGS((BYTE *, BYTE));
- Xextern LONG __stdargs asprintf __ARGS((BYTE *, BYTE *,...));
- Xextern LONG CompareDateStamps __ARGS((struct DateStamp *, struct DateStamp *));
- Xextern LONG CompFibs __ARGS((LONG, struct FileInfoBlock *, struct FileInfoBlock *));
- Xextern LONG FillFibEntry __ARGS((struct List *, struct FileInfoBlock *));
- Xextern LONG GetFileString __ARGS((BYTE *, BYTE *));
- Xextern LONG GetPathString __ARGS((BYTE *, BYTE *));
- Xextern LONG iswild __ARGS((BYTE *));
- Xextern LONG wildmatch __ARGS((BYTE *, BYTE *));
- Xextern VOID *myalloc __ARGS((LONG));
- Xextern VOID FibFileDate __ARGS((struct DateStamp *, BYTE *, BYTE *));
- Xextern VOID GetWinBounds __ARGS((LONG *, LONG *));
- Xextern VOID InsertFibNode __ARGS((struct List *, struct FibEntry *));
- Xextern VOID MakePathString __ARGS((struct FileLock *, BYTE *));
- Xextern VOID myfree __ARGS((VOID *));
- X
- X/* Local DATA */
- Xstruct DateStamp theolddate; /* Show files older than this date */
- Xstruct DateStamp thenewdate; /* Show files newer than this date */
- Xstruct FileHandle *ConOut; /* Standard output */
- Xstruct FileHandle *ConIn; /* Standard input */
- Xstruct FileLock *CurFLock = 0; /* Global Directory lock */
- Xstruct FileInfoBlock *GFibp = 0; /* Global FIB for Examine/ExNext */
- Xstruct InfoData *CurID = 0; /* Global InfoData for Info */
- XAPTR OldWindowPtr; /* Copy of what was in pr_WindowPtr */
- X
- X/* User flags (see ls.h for bit definitions) */
- XULONG LSFlags = SHOWDIRS | SHOWFILES;
- XULONG LSFlagsX = 0;
- XULONG oldsig = 0;
- X
- XLONG gentrycnt; /* Grand klugde used to control printing of gtotals */
- XLONG gdircount; /* Grand total # of dirs for Recursive */
- XLONG gfilecount; /* Grand total # of files found */
- XLONG gitemcnt; /* Grand kludge, the sequel ... for printing BS */
- XLONG gtotblocks; /* Grand total # of blocks */
- XLONG gtotbytes; /* Grand total # of bytes */
- X
- XLONG dircount; /* Number of directories found */
- XLONG filecount; /* Number of files found */
- XLONG totblocks; /* total # of blocks */
- XLONG totbytes; /* total # of bytes */
- XLONG maxnamlen; /* Longest name found */
- XLONG sortkey; /* 0=alpha, 1=size, 2=date, 3=diskkey */
- XLONG datefmt = AGE_TO_YEARS; /* format for date in new long listing */
- XLONG recurlevel = 0;
- XLONG recurlimit = MAXDEPTH;
- XLONG ioerrcode = 0;
- XLONG blksize = 0;
- X
- XBYTE padtab[PADTABSIZE]; /* Column table tab amounts */
- XBYTE initialpath[WORKSIZE]; /* Path where we were when started */
- XBYTE thePath[WORKSIZE]; /* Current filename space */
- XBYTE theDirPat[WORKSIZE]; /* Dirname pattern workspace */
- XBYTE theFilePat[WORKSIZE]; /* Filename pattern workspace */
- XBYTE workstr[WORKSIZE+64]; /* Temp string space */
- X
- XBYTE theblksstr[20];
- XBYTE thedatestr[12];
- XBYTE theprotstr[12];
- XBYTE thesizestr[20];
- XBYTE thetimestr[12];
- X
- XLONG CurWinRows = 0; /* Window bounds, determined at runtime */
- XLONG CurWinCols = 0;
- X
- X/* Initialized Strings */
- XBYTE Author[] = "\23333mls v4.0k\2330m \251 Copyright Kim E. DeVaughn 05/11/90 [non-k revs: J. McCormick]\n";
- XBYTE usage[] = "usage: ls [ [-options <args>] [names] ] ...\n";
- XBYTE usage0[] = " a Show dot files s Sort by size M Ignore case w/wildcard\n";
- XBYTE usage1[] = " b Show data blks t Sort by date N <name> Show newer than\n";
- XBYTE usage2[] = " c Show filenotes u Usage [also -?] O <name> Show older than\n";
- XBYTE usage3[] = " d Show dirs only v Vari col short list P Show full pathnames\n";
- XBYTE usage4[] = " e Execute bit is \"e\" x <pat> Exclude files Q Requesters enabled\n";
- XBYTE usage5[] = " f Show files only z Override blk calc R Recursive listing\n";
- XBYTE usage6[] = " h Show hidden files A Show all [= -ahi] S Show dirs first\n";
- XBYTE usage7[] = " i Show *.info files B <blk> Force blk size T Totals for all entries\n";
- XBYTE usage8[] = " k Sort by disk key C Single column list V Show rel pathnames\n";
- XBYTE usage9[] = " l Long listing D Show dirs last W No contents (wild dir)\n";
- XBYTE usage10[] = " m Mixed case output E No ANSI escape codes X <wide> Set output cols\n";
- XBYTE usage11[] = " n No sort G No subdir totals Y <high> Set output rows\n";
- XBYTE usage12[] = " o Old long list fmt H No headings Z Force ANSI sequences\n";
- XBYTE usage13[] = " p Append \"/\" to dirs I No page prompts 0-6 Date format (new long)\n";
- XBYTE usage14[] = " q Quit on not found K Show disk keys - Next arg is filename\n";
- XBYTE usage15[] = " r Reverse sort L <n> Limited recursion\n";
- XBYTE usage16[] = " F <format> Format output [-o fmt] (default: \"";
- XBYTE usage17[] = "\")\n";
- X
- X/* Date and output format strings */
- XBYTE baddatestr[] = "00-00-00";
- XBYTE badtimestr[] = "00:00:00";
- XBYTE datepat[] = "%02ld-%02ld-%02ld";
- XBYTE timepat[] = "%02ld:%02ld:%02ld";
- XBYTE dayspermonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
- XBYTE deffmtstr[40] = "%p %d %t %4b %8s %n\\n";
- XBYTE LongFmtStr[] = "%ld";
- XBYTE totalfmtstr[] = "Dirs: %-4ld Files: %-5ld Blocks: %-5ld Bytes: %-8ld\n";
- XBYTE filefmtstr[] = " Files: %-5ld Blocks: %-5ld Bytes: %-8ld\n";
- XBYTE TotHeaderMsg[] = "\nTotals:\n";
- XBYTE ColonStr[] = ":";
- XBYTE SlashStr[] = "/";
- XBYTE RamNameStr[] = "RAM:";
- Xchar *months[] = {"","Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"};
- Xchar exbit = 'x';
- X
- X/* ANSI color control strings */
- XBYTE penstr0[] = "\2330m"; /* Reset CON: */
- XBYTE penstr1[] = "\2330 p"; /* Cursor off */
- XBYTE penstr2[] = "\233 p"; /* Cursor on */
- XBYTE penstr3[] = "\23333m"; /* Color 3 NORM */
- XBYTE penstr4[] = "\2331;33;40m"; /* Color 3 BOLD */
- XBYTE penstr5[] = "\2331;31;40m"; /* Color 1 BOLD */
- XBYTE penstr6[] = "\2337;33m\2330 p"; /* Color 3 INV w/cursor off */
- X
- X/* CON: command sequence for window bounds report */
- XBYTE gwbrstr[4] = { 0x9b, '0', ' ', 'q' };
- X
- X/* Newline and "" source */
- X#define NULLSTR &NLine[1]
- XBYTE NLine[4] = {10, 0, 0, 0};
- XBYTE badopt[4] = {0, 0, 0, 0};
- X
- X/* Pointers to usage strings for quick easy output */
- XBYTE *usagestrs[] =
- X{
- X Author, usage, usage0, usage1, usage2, usage3, usage4, usage5,
- X usage6, usage7, usage8, usage9, usage10, usage11, usage12, usage13,
- X usage14, usage15, usage16, deffmtstr, usage17,
- X 0L
- X};
- X
- XBYTE *thefmtstr = deffmtstr; /* Format string pointer for long output */
- XBYTE *curpath;
- XBYTE *theAntiPat; /* Avoid pattern string */
- X
- X/* Local CODE */
- XBYTE *GetDecNum __ARGS((BYTE *, LONG *));
- XLONG CmpDateBounds __ARGS((struct DateStamp *));
- XLONG GetFileDate __ARGS((BYTE *, struct DateStamp *));
- XLONG ParseCmdOptions __ARGS((LONG, LONG, BYTE **));
- Xstruct FibEntry *AllocFib __ARGS((VOID));
- Xstruct FibEntry *ModNextFib __ARGS((struct FibEntry *, LONG));
- Xstruct List *GetDir __ARGS((struct FileLock *, struct FileInfoBlock *));
- XVOID DirIt __ARGS((struct FileLock *, BYTE *));
- XVOID FreeAllFibs __ARGS((struct List *));
- XVOID GetCLIArgs __ARGS((BYTE *, LONG *, BYTE **));
- XVOID LListDir __ARGS((struct List *));
- XVOID LListEntry __ARGS((struct FileInfoBlock *));
- XVOID LongList __ARGS((LONG *, LONG *, struct List *));
- XVOID PagePrompt __ARGS((LONG, LONG));
- XVOID ParseFormatOpts __ARGS((struct FileInfoBlock *));
- XVOID SetConPen __ARGS((BYTE *));
- XVOID SListDir __ARGS((struct List *));
- XVOID TestBreak __ARGS((VOID));
- XVOID Usage __ARGS((LONG));
- XVOID WCHR __ARGS((BYTE *));
- XVOID WSTR __ARGS((BYTE *));
- XVOID _main __ARGS((BYTE *));
- XLONG attrstr __ARGS((register BYTE *, register LONG *, register LONG *));
- XVOID fixNumBlocks __ARGS((struct FileLock *, FIB *));
- XLONG blkalloc __ARGS((register FIB *));
- XLONG datestr __ARGS((BYTE *, struct DateStamp *, LONG));
- XVOID cleanup __ARGS((LONG, LONG));
- XVOID errmsg __ARGS((BYTE *, LONG));
- XVOID llistentry __ARGS((register FIB *));
- X
- X
- X/*
- X * cleanup() - Unlock any locks we may have, free up allocations, turn the
- X * system requesters back on, and get on out ...
- X *
- X */
- X
- XVOID cleanup(result2, retcode)
- X LONG result2;
- X LONG retcode;
- X{
- X struct Process *procp;
- X
- X/* Make sure we unlock any locks we created! */
- X if ((CurFLock != 0) && ((LSFlags & PATHNAMED) != 0))
- X UnLock((BPTR)CurFLock);
- X
- X/* Free our fib and id */
- X if (GFibp != 0) myfree(GFibp);
- X if (CurID != 0) myfree(CurID);
- X
- X/* Put windowptr back */
- X procp = (struct Process *)FindTask(0L);
- X procp->pr_WindowPtr = OldWindowPtr;
- X
- X/* Set return status, exit */
- X procp->pr_Result2 = result2;
- X exit((int)retcode);
- X}
- X
- X
- X/*
- X * errmsg() - Print meaningful error messages when something screws up.
- X *
- X */
- X
- XVOID errmsg(fn, errcode)
- X BYTE *fn;
- X LONG errcode;
- X{
- X LONG len;
- X
- X/* Make sure we unlock any locks we created! */
- X if ((CurFLock != 0) && ((LSFlags & PATHNAMED) != 0))
- X {
- X UnLock((BPTR)CurFLock);
- X CurFLock = 0;
- X }
- X
- X if (errcode == -1L) errcode = ioerrcode = IoErr();
- X
- X len = strcspn(fn, ":") + 1;
- X strncpy(workstr, fn, len);
- X *(workstr + len) = '\0';
- X
- X switch(errcode)
- X {
- X case ERROR_NO_FREE_STORE:
- X WSTR("ls: Out of memory\n");
- X cleanup(errcode, 20L);
- X case ERROR_OBJECT_IN_USE:
- X asprintf(workstr, "%s: File or directory in use\n", fn);
- X break;
- X case ERROR_DIR_NOT_FOUND:
- X case ERROR_OBJECT_NOT_FOUND:
- X case ERROR_OBJECT_WRONG_TYPE:
- X asprintf(workstr, "%s: No such file or directory\n", fn);
- X break;
- X case ERROR_DISK_NOT_VALIDATED:
- X strcat(workstr, " Filesystem not validated\n");
- X break;
- X case ERROR_DEVICE_NOT_MOUNTED:
- X strcat(workstr, " Device not mounted or assigned\n");
- X break;
- X case ERROR_NOT_A_DOS_DISK:
- X strcat(workstr, " Invalid filesystem format [non-DOS]\n");
- X break;
- X case ERROR_NO_DISK:
- X strcat(workstr, " Device empty\n");
- X break;
- X case PATTERN_ERR:
- X WSTR("ls: Directory or filename pattern too long\n");
- X return;
- X case WILDSPEC_ERR:
- X asprintf(workstr, "%s: Unable to pattern match paths\n", fn);
- X break;
- X default:
- X asprintf(workstr, "ls: %s: Error - %ld\n", fn, errcode);
- X WSTR(workstr);
- X cleanup(errcode, 20L);
- X }
- X WSTR(workstr);
- X}
- X
- X
- X/*
- X * datestr() - Converts an AmigaDOS "datestamp" into an ASCII string in one
- X * of several defined formats.
- X *
- X * A non-zero return indicates an unknown format was requested,
- X * in which case the return string is null'd.
- X *
- X */
- X
- XLONG datestr(s, ds, format)
- X BYTE *s;
- X struct DateStamp *ds;
- X LONG format;
- X{
- X register LONG t, mo, yr;
- X LONG y2, day, hr, min, sec;
- X struct DateStamp cds;
- X
- X t = ds->ds_Days - 2251; /* This date algorithm by Tom Rokicki. */
- X yr = (4 * t + 3) / 1461; /* It was taken from Rob Peck's book: */
- X t -= 1461 * yr / 4; /* "Programmer's Guide to the Amiga", */
- X yr += 1984; /* and is supposed to be good until 2100; */
- X mo = (5 * t + 2) / 153; /* doesn't work for dates before 03/01/84 */
- X day = t - ((153 * mo + 2) / 5) + 1;
- X mo += 3;
- X if (mo > 12) {
- X yr++;
- X mo -= 12;
- X }
- X y2 = (yr < 2000) ? yr-1900 : yr-2000; /* after 2099 ... punt! */
- X
- X
- X t = ds->ds_Minute * 60 + ds->ds_Tick/TICKS_PER_SECOND;
- X sec = t % 60; t /= 60;
- X min = t % 60; t /= 60;
- X hr = t % 24;
- X
- X
- X switch (format) {
- X
- X case AGE_TO_YEARS :
- X DateStamp(&cds);
- X if (((cds.ds_Days - ds->ds_Days) > TIME_YEAR_THRESHOLD) ||
- X ((cds.ds_Days - ds->ds_Days) < 0)) {
- X asprintf(s, "%s %2ld %5ld\0", months[mo], day, yr);
- X } else {
- X asprintf(s, "%s %2ld %02ld:%02ld\0", months[mo], day, hr, min);
- X }
- X break;
- X
- X case FULL_FORM :
- X asprintf(s, "%s %02ld %4ld %02ld:%02ld:%02ld\0", months[mo], day, yr, hr, min, sec);
- X break;
- X
- X case DASHA_FORM :
- X asprintf(s, "%02ld-%s-%02ld %02ld:%02ld:%02ld\0", day, months[mo], y2, hr, min, sec);
- X break;
- X
- X case DASHN_FORM :
- X asprintf(s, "%02ld-%02ld-%02ld %02ld:%02ld:%02ld\0", mo, day, y2, hr, min, sec);
- X break;
- X
- X case SLASH_FORM :
- X asprintf(s, "%02ld/%02ld/%02ld %02ld:%02ld:%02ld\0", mo, day, y2, hr, min, sec);
- X break;
- X
- X case EURO_FORM :
- X asprintf(s, "%02ld/%02ld/%02ld %02ld:%02ld:%02ld\0", day, mo, y2, hr, min, sec);
- X break;
- X
- X case DOT_FORM :
- X asprintf(s, "%02ld.%02ld.%02ld %02ld:%02ld:%02ld\0", y2, mo, day, hr, min, sec);
- X break;
- X
- X default :
- X *s = '\0'; /* bad format ... null out the filedate string */
- X return(1);
- X }
- X return(0);
- X}
- X
- X
- X/*
- X * attrstr() - Converts FileInfoBlock DirEntryType & Protection entries into
- X * an ASCII string representation. Format is:
- X *
- X * dhsparwxd ["h" may possibly be replaced by "H" or "+"]
- X *
- X * where a letter is replaced by a "-" if the corresponding
- X * attribute is not associated with the current FIB entry (i.e.,
- X * if the bit is not "true"). [The "H" or "+" form indicates
- X * one or more of the currently reserved/undefined high-order
- X * bits (as of 1.3) are on. An "H" is used if the "hidden" bit
- X * is also on ... a "+" is used if it is not.]
- X *
- X * A non-zero return code indicates the "H" or "+" form was
- X * detected.
- X *
- X * Note: Due to historical braindamage in AmigaDOS, bits 0-3
- X * (the original "protection" bits) are "active low",
- X * while bits 4-7 (more properly called "attribute" bits)
- X * are "active high". At least this is based on the way
- X * the 1.3 Delete, Resident, Shell, and Protect commands
- X * interpret the "d", "p", and "s" bits (and how the List
- X * command displays them). [ Thanks alot Tim ...! ]
- X *
- X */
- X
- XLONG attrstr(s, type, prot)
- X register BYTE *s;
- X register LONG *type;
- X register LONG *prot;
- X{
- X BYTE *t;
- X
- X t = s;
- X *s++ = (*type > 0) ? 'd' : '-';
- X *s++ = (*prot & FIBF_HIDDEN) ? 'h' : '-';
- X *s++ = (*prot & FIBF_SCRIPT) ? 's' : '-';
- X *s++ = (*prot & FIBF_PURE) ? 'p' : '-';
- X *s++ = (*prot & FIBF_ARCHIVE) ? 'a' : '-';
- X *s++ = (*prot & FIBF_READ) ? '-' : 'r';
- X *s++ = (*prot & FIBF_WRITE) ? '-' : 'w';
- X *s++ = (*prot & FIBF_EXECUTE) ? '-' : exbit;
- X *s++ = (*prot & FIBF_DELETE) ? '-' : 'd';
- X *s = '\0';
- X
- X if (*prot & FIBF_RESERVED) {
- X if (*prot & FIBF_HIDDEN) {
- X t[1] = 'H';
- X } else {
- X t[1] = '+';
- X }
- X return(1);
- X }
- X return(0);
- X}
- X
- X
- X/*
- X * fixNumBlocks() - A hack to fix the fib_NumBlocks field so it is correct.
- X *
- X * It was busted with the introduction of the FFS in AmigaDOS 1.3. Don't
- X * ask where this is documented ... as far as I know, it isn't not in the
- X * 1.3 includes, autodocs, readme's, user's manual, RKM's, or DevCon notes.
- X * It is possible it may be mentioned in an AmigaMail (that wonderfully
- X * regular publication), and I'm told it was mentioned once in a message on
- X * USENET.
- X *
- X * Helluva way to run a ship ...
- X *
- X * As may be ... since fib_NumBlocks was in use thruout this code before
- X * this was discovered, it was easiest to just fixup the fib_NumBlocks when
- X * the file/dir gets initially Examine/ExNext'd, with a call to Info() for
- X * *all* files (which means alot of unnecessary calls get made [for files
- X * all in the same dir, etc]). The performance penalty ends up being about
- X * 1 sec, for a tree with 537 entries (which seems acceptable to me).
- X *
- X * If you don't like it ... I suggest you complain to CBM about their, er,
- X * uhmm, "documentation" efforts!
- X *
- X * Helluva way to run a ship ...
- X *
- X * /kim /\;;/\
- X *
- X */
- X
- XVOID fixNumBlocks(lock, fib)
- X struct FileLock *lock;
- X FIB *fib;
- X{
- X LONG *nb;
- X LONG bsize;
- X static int errflag = 0;
- X
- X if ((LSFlagsX & NOFIXNUMBLOCKS) != 0) return;
- X
- X if (blksize == 0)
- X {
- X /* Try to fill InfoData, bomb if not readable for some reason (like */
- X if (Info((BPTR)lock, CurID) == 0) /* ls'ing a "pathass'd" assign) */
- X {
- X /* Print error msg only once, and only if we'll be printing block counts */
- X if ((errflag == 0) && ((LSFlags & (LONGLIST | TOTALIZE)) != 0))
- X {
- X errflag++;
- X asprintf(workstr, "\nls: warning (%ld): block count(s) may be inaccurate - see ls.doc\n\n", IoErr());
- X WSTR(workstr);
- X }
- X return;
- X }
- X else
- X bsize = CurID->id_BytesPerBlock;
- X }
- X else
- X bsize = blksize;
- X
- X nb = (LONG *)&(fib->fib_NumBlocks);
- X *nb = (fib->fib_Size / bsize) + ((fib->fib_Size % bsize) ? 1 : 0);
- X}
- X
- X
- X/*
- X * blkalloc() - Returns the actual number of blocks allocated by a file/dir
- X * (or just the data blocks, if DATABLKSONLY is set).
- X *
- X * Assumes 1.3 original or fast filesystem (and a fixed up fib_NumBlocks).
- X *
- X */
- X
- XLONG blkalloc(fib)
- X register FIB *fib;
- X{
- X if ((LSFlagsX & DATABLKSONLY) == 0) {
- X return(fib->fib_NumBlocks +
- X (fib->fib_NumBlocks / MAX_BLKS_PER_EXTENT) +
- X ((fib->fib_NumBlocks % MAX_BLKS_PER_EXTENT) ? 1 : 0) +
- X ((fib->fib_Size == 0) ? 1 : 0) /* kludge for 0-len files (and dirs) */
- X );
- X } else {
- X return(fib->fib_NumBlocks);
- X }
- X}
- X
- X
- X/*
- X * llistentry() - Prints the data in a FIB entry.
- X *
- X */
- X
- XVOID llistentry(fib)
- X register FIB *fib;
- X{
- X BYTE tbuf[64]; /* shouldn't exceed about 47-53 chars max (but add some pad) */
- X LONG len;
- X
- X attrstr(workstr, &(fib->fib_DirEntryType), &(fib->fib_Protection));
- X
- X if (fib->fib_Comment[0] == 0) {
- X strcat(workstr, " ");
- X } else {
- X strcat(workstr, " c");
- X }
- X
- X if ((LSFlags & SHOWDISKKEYS) != 0)
- X {
- X asprintf(tbuf, " %6ld", fib->fib_DiskKey);
- X strcat(workstr, tbuf);
- X }
- X
- X asprintf(tbuf, " %5ld %8ld ", blkalloc(fib), fib->fib_Size);
- X strcat(workstr, tbuf);
- X
- X datestr(tbuf, &(fib->fib_Date), datefmt);
- X strcat(workstr, tbuf);
- X strcat(workstr, " ");
- X
- X WSTR(workstr);
- X
- X if (fib->fib_DirEntryType > 0) SetConPen(penstr3);
- X
- X *workstr = '\0';
- X if (((LSFlags & RELPATHNAMES) != 0) || ((LSFlags & FULLPATHNAMES) != 0))
- X {
- X strcat(workstr, curpath);
- X len = strlen(workstr);
- X if ((len > 1) && (*(workstr + len - 1) != ':'))
- X strcat(workstr, "/");
- X }
- X
- X strcat(workstr, fib->fib_FileName);
- X
- X len = 0;
- X if ((LSFlags & RELPATHNAMES) != 0)
- X {
- X len = strlen(initialpath);
- X if ((strnicmp(workstr, initialpath, len) == 0) && (len < strlen(workstr)))
- X {
- X if (*(workstr + len) == '/')
- X len++;
- X }
- X else
- X len = 0;
- X }
- X
- X if (((LSFlags & ADDDIRSLASH) != 0) && (fib->fib_DirEntryType > 0))
- X strcat(workstr, "/");
- X
- X/* commented out until there is more support for NOT defaulting to "x" */
- X/* if (workstr[0] == 'd') {
- X * strcat(workstr, "/");
- X * } else if (workstr[7] != '-') {
- X * strcat(workstr, "*");
- X * }
- X */
- X
- X strcat(workstr, "\n");
- X WSTR(workstr + len);
- X
- X if (fib->fib_DirEntryType > 0) SetConPen(penstr0);
- X
- X if (((LSFlags & NOTEFLAG) != 0) && (fib->fib_Comment[0] != 0))
- X {
- X SetConPen(penstr3);
- X asprintf(workstr, "\"%s\"\n", fib->fib_Comment);
- X WSTR (workstr);
- X SetConPen(penstr0);
- X }
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Allocate a FibEntry structure and associated FileInfoBlock.
- X * -------------------------------------------------------------------- */
- Xstruct FibEntry *AllocFib()
- X{
- X struct FibEntry *tfibp;
- X
- X if ((tfibp = myalloc((LONG)(sizeof(struct FibEntry) + sizeof(struct FileInfoBlock)))) != 0)
- X {
- X tfibp->fe_Fib = (struct FileInfoBlock *)((ULONG)tfibp + sizeof(struct FibEntry));
- X }
- X else
- X LSFlags |= BREAKFLAG;
- X return(tfibp);
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Use AmigaDOS to output a string to the stdout channel
- X * -------------------------------------------------------------------- */
- XVOID WSTR(tstring)
- X BYTE *tstring;
- X{
- X LONG i;
- X
- X i = strlen(tstring);
- X if (i > 0)
- X {
- X (VOID) Write((BPTR)ConOut, tstring, i);
- X }
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Use AmigaDOS to put a character to the stdout
- X * -------------------------------------------------------------------- */
- XVOID WCHR(ch)
- X BYTE *ch;
- X{
- X (VOID) Write((BPTR)ConOut, ch, 1L);
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Check to see if the user hit ^C
- X *
- X * Coded in this arcane fashion since there seems to be a race/etc. between
- X * the SetSignal() call, and the WSTR() and or'ing in of the BREAKFLAG. If
- X * the outer "if" is omitted, "**BREAK" prints 3 times; if the outer "else"
- X * is omitted, the BREAKFLAG doesn't seem to get or'd in ... grumble, swear!
- X *
- X * As my be ... this is an ugly hack, but it seems to work ...
- X *
- X * C'est la vie ... /kim
- X *
- X * -------------------------------------------------------------------- */
- XVOID TestBreak ()
- X{
- X if ((oldsig & SIGBREAKF_CTRL_C) == 0)
- X {
- X oldsig = SetSignal (0L, 0L);
- X if ((oldsig & SIGBREAKF_CTRL_C) != 0)
- X {
- X WSTR ("\2330m\233 p**BREAK\n");
- X LSFlags |= BREAKFLAG;
- X }
- X }
- X else
- X {
- X LSFlags |= BREAKFLAG;
- X }
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Prompt the user to hit return, wait till return is hit
- X * -------------------------------------------------------------------- */
- XVOID PagePrompt (page, maxpage)
- X LONG page, maxpage;
- X{
- X if ((CurWinCols > maxnamlen) && (page > 1) && ((LSFlags & NOINTERACT) == 0))
- X {
- X SetConPen(penstr6);
- X asprintf(workstr, " More (%ld of %ld) ... ", (page - 1), maxpage);
- X if (CurWinCols <= strlen(workstr))
- X strcpy(workstr, "More ... ");
- X WSTR(workstr);
- X SetConPen(penstr0);
- X (VOID) Read((BPTR)ConIn, workstr, (long)WORKSIZE);
- X WSTR("\2330 p\233F\233K");
- X TestBreak();
- X }
- X}
- X
- X
- X/* -------------------------------------------------------------------- */
- Xstruct FibEntry *ModNextFib(tfibp, rows)
- X struct FibEntry *tfibp;
- X LONG rows;
- X{
- X LONG i;
- X
- X for (i = 0; i < rows && tfibp->fe_Node.mln_Succ != 0; i++)
- X {
- X tfibp = (struct FibEntry *)tfibp->fe_Node.mln_Succ;
- X }
- X return(tfibp);
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * set CON: character color to default Pen1 colors
- X * -------------------------------------------------------------------- */
- XVOID SetConPen (penstr)
- X BYTE *penstr;
- X{
- X if ((LSFlags & CONSOLE) != 0)
- X WSTR (penstr);
- X}
- X
- X
- X/* #define DEBUGSLD 1 */
- X/* --------------------------------------------------------------------
- X * List a FibEntry list in a compact fashion
- X * -------------------------------------------------------------------- */
- XVOID SListDir (fibheadp)
- X struct List *fibheadp;
- X{
- X LONG avglen;
- X LONG colcnt;
- X LONG currow;
- X LONG dfcount;
- X LONG i, j, wlen;
- X LONG maxcol;
- X LONG maxpage;
- X LONG maxrow;
- X LONG maxwinrow;
- X LONG minpad = 2; /* minimum number of blanks between listing entries */
- X LONG pagecnt;
- X LONG rowcnt;
- X LONG tlen;
- X LONG totlen;
- X struct FibEntry *hfibp, *tfibp;
- X
- X SetConPen (penstr1); /* Turn the cursor off since it will blink anyway */
- X GetWinBounds (&colcnt, &currow); /* Get current window size */
- X
- X if (CurWinCols == 0)
- X CurWinCols = colcnt;
- X if (CurWinRows == 0)
- X CurWinRows = currow;
- X
- X if ((LSFlags & VARCOLSFORMAT) != 0)
- X {
- X /* Make a average-case WxH estimate for # of display columns */
- X for (totlen = dfcount = 0, hfibp = (struct FibEntry *)fibheadp->lh_Head;
- X hfibp->fe_Node.mln_Succ != 0;
- X hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ)
- X {
- X if (hfibp->fe_Fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) == 0)
- X (VOID) strcat (hfibp->fe_Fib->fib_FileName, SlashStr);
- X totlen += strlen (hfibp->fe_Fib->fib_FileName);
- X dfcount++;
- X if (((LSFlags & WILDPATH) != 0) && (hfibp->fe_Fib->fib_DirEntryType > 0))
- X {
- X totlen -= strlen (hfibp->fe_Fib->fib_FileName);
- X dfcount--;
- X }
- X }
- X if (dfcount == 0) dfcount++;
- X
- X /* Calc average length of all entries */
- X avglen = totlen / dfcount; /* Avg name length = totlen/numentries */
- X if ((totlen % dfcount) != 0)
- X avglen++;
- X
- X /* Longest name wider than window, or single column flag set? */
- X if ((CurWinCols <= maxnamlen) || ((LSFlags & ONECOLFORMAT) != 0))
- X maxcol = 1; /* Yep, just print one column */
- X else
- X {
- X /* Else maxcols = winwidth/namewidth */
- X for (maxcol = 0, colcnt = CurWinCols; colcnt >= avglen; maxcol++)
- X {
- X colcnt -= avglen + 2;
- X }
- X }
- X#ifdef DEBUGSLD
- X asprintf(workstr, "avg:%ld max:%ld\n", avglen, maxnamlen); WSTR(workstr);
- X#endif
- X
- X /* Dry run output avg-case WxH table to see if it needs adjusting */
- X for (;;)
- X {
- X /* Clear out previous padtab */
- X memset(padtab, 0, PADTABSIZE);
- X
- X /* Number of rows = total entries / entries per row */
- X maxrow = dfcount / maxcol;
- X if ((dfcount % maxcol) != 0) /* Round up if non-integral */
- X maxrow++;
- X#ifdef DEBUGSLD
- X asprintf(workstr, "avg: %ld rows by %ld cols\n", maxrow, maxcol); WSTR(workstr);
- X#endif
- X
- X for (rowcnt = 0, hfibp = (struct FibEntry *)fibheadp->lh_Head;
- X rowcnt < maxrow && hfibp->fe_Node.mln_Succ != 0;
- X rowcnt++, hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ)
- X {
- X for (colcnt = 0, tfibp = hfibp;
- X colcnt < maxcol && tfibp->fe_Node.mln_Succ != 0;
- X colcnt++, tfibp = ModNextFib (tfibp, maxrow))
- X {
- X if (~(((LSFlags & WILDPATH) != 0) && (tfibp->fe_Fib->fib_DirEntryType > 0)))
- X {
- X tlen = strlen (tfibp->fe_Fib->fib_FileName);
- X if (tlen > padtab[colcnt])
- X padtab[colcnt] = tlen;
- X }
- X }
- X
- X /* If this is the first row, calc actual maxcol/maxrow for this dfcount */
- X if (rowcnt == 0)
- X {
- X maxcol = colcnt;
- X maxrow = dfcount / maxcol;
- X if ((dfcount % maxcol) != 0) /* Round up if non-integral */
- X maxrow++;
- X }
- X }
- X
- X /* Calculate actual total width by adding up width of all columns */
- X for (colcnt = totlen = 0; (colcnt + 1) < maxcol; colcnt++)
- X {
- X totlen += (LONG)padtab[colcnt] + 2;
- X#ifdef DEBUGSLD
- X asprintf(workstr, "padtab[%ld]=%ld\n", colcnt, (LONG)padtab[colcnt]); WSTR(workstr);
- X#endif
- X }
- X totlen += (LONG)padtab[colcnt];
- X#ifdef DEBUGSLD
- X asprintf(workstr, "padtab[%ld]=%ld\n", colcnt, (LONG)padtab[colcnt]); WSTR(workstr);
- X asprintf(workstr, "totlen %ld\n", totlen); WSTR(workstr);
- X#endif
- X
- X /* if More than one column and
- X * total width of all columns is greater > our window width,
- X * then decrease number of display columns
- X */
- X if ((maxcol > 1) && (totlen > CurWinCols))
- X {
- X maxcol--;
- X#ifdef DEBUGSLD
- X asprintf(workstr, "new maxcol:%ld\n", maxcol); WSTR(workstr);
- X#endif
- X }
- X else
- X break;
- X }
- X#ifdef DEBUGSLD
- X asprintf(workstr, "adjusted: maxrow:%ld maxcol:%ld (winwidth:%ld totlen:%ld)\n", maxrow, maxcol, CurWinCols, totlen); WSTR(workstr);
- X#endif
- X
- X }
- X else
- X {
- X
- X if ((LSFlags & ADDDIRSLASH) != 0)
- X maxnamlen += 1;
- X
- X for (dfcount = 0, hfibp = (struct FibEntry *)fibheadp->lh_Head;
- X hfibp->fe_Node.mln_Succ != 0;
- X hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ)
- X {
- X if ((LSFlags & ADDDIRSLASH) != 0)
- X if (hfibp->fe_Fib->fib_DirEntryType > 0)
- X (VOID) strcat (hfibp->fe_Fib->fib_FileName, SlashStr);
- X else
- X (VOID) strcat (hfibp->fe_Fib->fib_FileName, " ");
- X dfcount++;
- X if (((LSFlags & WILDPATH) != 0) && (hfibp->fe_Fib->fib_DirEntryType > 0))
- X dfcount--;
- X }
- X
- X if ((CurWinCols <= maxnamlen) || ((LSFlags & ONECOLFORMAT) != 0))
- X maxcol = 1;
- X else
- X maxcol = CurWinCols / (maxnamlen + minpad);
- X maxrow = dfcount / maxcol;
- X if ((dfcount % maxcol) != 0)
- X maxrow++;
- X memset(padtab, 0, PADTABSIZE);
- X for (colcnt = 0; colcnt < maxcol; colcnt++)
- X padtab[colcnt] = maxnamlen;
- X }
- X
- X/* Calc number of pages */
- X maxwinrow = CurWinRows - 1; /* was -3 in v3.1 */
- X if (maxwinrow <= 0)
- X maxwinrow = 1;
- X pagecnt = 1;
- X maxpage = maxrow / maxwinrow;
- X if ((maxrow % maxwinrow) != 0)
- X maxpage++;
- X
- X/* Do actual output scan */
- X for (rowcnt = 0, currow = maxwinrow, hfibp = (struct FibEntry *)fibheadp->lh_Head;
- X (LSFlags & BREAKFLAG) == 0 && rowcnt < maxrow && hfibp->fe_Node.mln_Succ != 0;
- X TestBreak(), rowcnt++, currow++, hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ)
- X {
- X if ((maxpage > 1) && (currow == maxwinrow))
- X {
- X currow = 0;
- X if ((LSFlags & CONSOLE) != 0)
- X {
- X PagePrompt (pagecnt, maxpage);
- X if ((LSFlags & BREAKFLAG) != 0)
- X break;
- X }
- X pagecnt++;
- X }
- X
- X for (colcnt = 0, tfibp = hfibp;
- X colcnt < maxcol && tfibp->fe_Node.mln_Succ != 0;
- X colcnt++)
- X {
- X if (tfibp->fe_Fib->fib_DirEntryType < 0)
- X {
- X /* Print a file entry */
- X (VOID) stpcpy (workstr, tfibp->fe_Fib->fib_FileName);
- X wlen = strlen (workstr);
- X }
- X else
- X {
- X /* Print a directory entry */
- X workstr[0] = 0;
- X wlen = 0;
- X
- X if ((LSFlags & WILDPATH) == 0)
- X {
- X wlen = strlen (tfibp->fe_Fib->fib_FileName);
- X if ((LSFlags & CONSOLE) != 0)
- X (VOID) strcat (workstr, penstr3);
- X (VOID) strcat (workstr, tfibp->fe_Fib->fib_FileName);
- X if ((LSFlags & CONSOLE) != 0)
- X (VOID) strcat (workstr, penstr0);
- X }
- X }
- X
- X /* Move along list to the next entry, mod maxcol, print this entry */
- X tfibp = ModNextFib (tfibp, maxrow);
- X
- X /* If this is not the last column, pad with spaces till we get to next column */
- X if ((colcnt + 1) < maxcol && tfibp->fe_Node.mln_Succ != 0)
- X {
- X for (i = (LONG)padtab[colcnt] - 1 + minpad, j = strlen (workstr); i >= wlen; i--, j++)
- X workstr[j] = ' ';
- X workstr[j] = 0;
- X }
- X /* Output the final entry */
- X WSTR(workstr);
- X }
- X
- X /* Filled this row, start next down */
- X WCHR(NLine);
- X }
- X SetConPen(penstr2); /* Turn cursor back on */
- X}
- X
- X
- X/* -------------------------------------------------------------------- */
- XBYTE *GetDecNum (cp, spccnt)
- X BYTE *cp;
- X LONG *spccnt;
- X{
- X for (*spccnt = 0; *cp >= '0' && *cp <= '9'; cp++)
- X {
- X *spccnt = *spccnt * 10 + (LONG)*cp - '0';
- X }
- X return (cp);
- X}
- X
- X
- X/* -------------------------------------------------------------------- */
- XVOID ParseFormatOpts (fib)
- X struct FileInfoBlock *fib;
- X{
- X BYTE *cp1, *cp2, *reps;
- X BYTE *pathend, *thenamestr;
- X LONG i, spccnt;
- X
- X i = strlen (curpath);
- X pathend = curpath + i;
- X if (i > 1 && *(curpath + i - 1) != ':')
- X {
- X *(curpath + i) = '/';
- X i++;
- X *(curpath + i) = 0;
- X }
- X thenamestr = curpath + strlen(curpath);
- X cp2 = thenamestr;
- X if (fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) != 0)
- X cp2 = stpcpy (cp2, penstr3);
- X cp2 = stpcpy (cp2, fib->fib_FileName);
- X if (fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) != 0)
- X (VOID) stpcpy (cp2, penstr0);
- X
- X for (cp1 = workstr, cp2 = thefmtstr; *cp2 != 0; cp2++)
- X {
- X if (*cp2 != '%' && *cp2 != '\\')
- X *cp1++ = *cp2;
- X else
- X {
- X if (*cp2 == '%')
- X {
- X cp2++;
- X cp2 = GetDecNum (cp2, &spccnt);
- X if (spccnt > 99)
- X {
- X spccnt = 99;
- X }
- X
- X switch (*cp2)
- X {
- X case 'p':
- X reps = theprotstr;
- X break;
- X case 'd':
- X reps = thedatestr;
- X break;
- X case 't':
- X reps = thetimestr;
- X break;
- X case 'b':
- X reps = theblksstr;
- X break;
- X case 's':
- X reps = thesizestr;
- X break;
- X case 'n':
- X if (fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) != 0 && spccnt > 0)
- X spccnt += 7;
- X if ((LSFlags & FULLPATHNAMES) != 0)
- X reps = curpath;
- X else
- X reps = thenamestr;
- X break;
- X case '%':
- X *cp1++ = '%';
- X *cp1++ = 0;
- X default:
- X reps = NULLSTR;
- X }
- X for (i = strlen(reps); i < spccnt; i++)
- X *cp1++ = ' ';
- X cp1 = stpcpy (cp1, reps);
- X }
- X else
- X {
- X cp2++;
- X switch (*cp2)
- X {
- X case 'n':
- X *cp1++ = '\n';
- X break;
- X case 't':
- X *cp1++ = '\t';
- X break;
- X case '\\':
- X *cp1++ = '\\';
- X break;
- X }
- X *cp1 = 0;
- X }
- X }
- X }
- X WSTR(workstr);
- X
- X if ((LSFlags & NOTEFLAG) != 0 && fib->fib_Comment[0] != 0)
- X {
- X SetConPen(penstr3);
- X (VOID)asprintf(workstr, "/* %s */\n", fib->fib_Comment);
- X WSTR (workstr);
- X SetConPen(penstr0);
- X }
- X *pathend = 0;
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Verbosely list a particular FibEntry
- X * -------------------------------------------------------------------- */
- XVOID LListEntry (fib)
- X struct FileInfoBlock *fib;
- X{
- X LONG i;
- X LONG pmodes;
- X
- X pmodes = fib->fib_Protection & 0xff;
- X (VOID)stpcpy (theprotstr, "chsparw7d");
- X theprotstr[7] = exbit;
- X for (i = 3; i >= 0; i--)
- X {
- X if ((pmodes & (1 << i)) != 0)
- X theprotstr[8 - i] = '-';
- X if ((pmodes & (1 << (i + 4))) == 0)
- X theprotstr[4 - i] = '-';
- X }
- X
- X if (fib->fib_Comment[0] == 0)
- X theprotstr[0] = '-';
- X
- X FibFileDate(&fib->fib_Date, thedatestr, thetimestr);
- X
- X if (fib->fib_DirEntryType > 0)
- X {
- X if ((LSFlagsX & DATABLKSONLY) != 0)
- X stpcpy(theblksstr, "0");
- X else
- X stpcpy(theblksstr, "1");
- X stpcpy (thesizestr, "Dir");
- X }
- X else
- X {
- X asprintf(theblksstr, LongFmtStr, blkalloc(fib));
- X asprintf(thesizestr, LongFmtStr, fib->fib_Size);
- X }
- X ParseFormatOpts(fib);
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * List a directory in a verbose informative manner
- X * -------------------------------------------------------------------- */
- XVOID LListDir (fibheadp)
- X struct List *fibheadp;
- X{
- X struct FibEntry *tfibp;
- X
- X SetConPen(penstr1);
- X
- X totblocks = totbytes = 0;
- X for (tfibp = (struct FibEntry *)fibheadp->lh_Head;
- X tfibp->fe_Node.mln_Succ != 0;
- X tfibp = (struct FibEntry *)tfibp->fe_Node.mln_Succ)
- X {
- X TestBreak();
- X if ((LSFlags & BREAKFLAG) != 0)
- X return;
- X
- X if ((tfibp->fe_Fib->fib_DirEntryType > 0) && ((LSFlags & WILDPATH) != 0))
- X {
- X ; /* seems to be a Lattice v5.04a bug ... negating the test and putting the "else" here doesn't work */
- X }
- X else
- X {
- X if ((LSFlags & OLDLONGFORMAT) != 0)
- X LListEntry (tfibp->fe_Fib);
- X else
- X llistentry (tfibp->fe_Fib);
- X
- X totblocks += blkalloc(tfibp->fe_Fib);
- X totbytes += tfibp->fe_Fib->fib_Size;
- X }
- X }
- X
- X if ((LSFlags & (BREAKFLAG | NODIRTOTAL)) == 0)
- X {
- X if ((LSFlags & WILDPATH) == 0)
- X {
- X if ((dircount + filecount) > 1)
- X {
- X asprintf(workstr, totalfmtstr, dircount, filecount, totblocks, totbytes);
- X WSTR(workstr);
- X }
- X }
- X else
- X {
- X if (filecount > 1)
- X {
- X asprintf(workstr, filefmtstr, filecount, totblocks, totbytes);
- X WSTR(workstr);
- X }
- X }
- X }
- X SetConPen(penstr2);
- X}
- X
- X
- X/* -------------------------------------------------------------------- */
- XLONG CmpDateBounds (tdate)
- X struct DateStamp *tdate;
- X{
- X if ((LSFlags & SHOWNEWERTHAN) != 0)
- X {
- X if (CompareDateStamps(&thenewdate, tdate) >= 0)
- X return (0L);
- X }
- X if ((LSFlags & SHOWOLDERTHAN) != 0)
- X {
- X if (CompareDateStamps(tdate, &theolddate) >= 0)
- X return (0L);
- X }
- X return (1L);
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Free up memory allocated to a linked list of FibEntrys
- X * -------------------------------------------------------------------- */
- XVOID FreeAllFibs (fibheadp)
- X struct List *fibheadp;
- X{
- X struct FibEntry *tfibp;
- X
- X if (fibheadp != 0)
- X {
- X while (fibheadp->lh_Head->ln_Succ != 0)
- X {
- X tfibp = (struct FibEntry *)RemTail(fibheadp);
- X myfree(tfibp);
- X }
- X
- X /* Now free the MinList itself */
- X myfree(fibheadp);
- X }
- X}
- X
- X
- X/* --------------------------------------------------------------------
- X * Allocate and fill a linked list of FileInfoBlocks
- X * -------------------------------------------------------------------- */
- Xstruct List *GetDir (lockp, fibp)
- X struct FileLock *lockp;
- X struct FileInfoBlock *fibp;
- X{
- X BYTE *thepat; /* Pattern pointer to dir or file pattern */
- X LONG dfcount;
- X LONG matchstat; /* Result of wildmatch() */
- X LONG nextstat; /* Status of ExNext() */
- X LONG tempnamlen; /* Compare length for strings */
- X LONG tmpflags;
- X struct List *fibhead; /* Temp list of Fibs created */
- X struct List *dirhead; /* Temp list of dirs if SHOWDIRS == 0 */
- X
- X maxnamlen = dfcount = dircount = filecount = 0L;
- X
- X/* Initialize an exec list of nodes, zero entries */
- X if ((fibhead = myalloc ((LONG)sizeof(struct MinList))) == 0)
- X return (0L);
- X NewList (fibhead);
- X
- X/* Allocate an separate list for directories that don't match specs */
- X if ((dirhead = myalloc((LONG)sizeof(struct MinList))) == 0)
- X goto BADALLOC;
- X NewList (dirhead);
- X
- X do
- X {
- X TestBreak ();
- X if ((LSFlags & BREAKFLAG) != 0)
- X goto GOODRET;
- X
- X /* If we got something */
- X if ((nextstat = ExNext ((BPTR)lockp, fibp)) != 0)
- X {
- X /* If the entry is wanted bump count of files or directories */
- X if (CmpDateBounds (&fibp->fib_Date) != 0)
- X {
- X if (fibp->fib_DirEntryType > 0) /* It's a directory */
- X thepat = theDirPat;
- X else
- X thepat = theFilePat;
- X
- X matchstat = wildmatch (fibp->fib_FileName, thepat);
- X
- X if ((LSFlags & MATCHINFOFILES) == 0 && matchstat != 0)
- X {
- X tmpflags = LSFlags;
- X LSFlags |= IGNORECASEWILD;
- X matchstat = wildmatch (fibp->fib_FileName, "*.info") ^ 1;
- X LSFlags = tmpflags;
- X }
- X if ((LSFlags & MATCHDOTFILES) == 0 && matchstat != 0)
- X matchstat = wildmatch (fibp->fib_FileName, ".*") ^ 1;
- X if ((LSFlags & ANTIMATCH) != 0 && matchstat != 0)
- X matchstat = wildmatch (fibp->fib_FileName, theAntiPat) ^ 1;
- X if ((fibp->fib_Protection & FIBF_HIDDEN) != 0)
- X matchstat = (LSFlags & SHOWHIDDEN) ? 1 : 0;
- X
- X if (matchstat == 0) /* No match? Then move on */
- X continue;
- X
- X dfcount++; /* we found something of interest */
- X
- X if (fibp->fib_DirEntryType > 0) /* It's a directory */
- X {
- X if (FillFibEntry (dirhead, fibp) == 0)
- X goto BADALLOC;
- X if ((LSFlags & SHOWDIRS) != 0)
- X {
- X dircount++; gdircount++; gitemcnt++;
- X
- X if ((LSFlagsX & DATABLKSONLY) == 0)
- X gtotblocks++;
- X }
- X else
- X continue;
- X }
- X else /* It's a file entry */
- X {
- X if ((LSFlags & SHOWFILES) != 0)
- X {
- X filecount++; gfilecount++; gitemcnt++;
- X fixNumBlocks(lockp, fibp);
- X gtotblocks += blkalloc(fibp);
- X gtotbytes += fibp->fib_Size;
- X }
- X else /* Don't want this file, move on to next entry */
- X continue;
- X }
- X
- X /* See if this is the longest filename for later use in listing */
- X tempnamlen = strlen (fibp->fib_FileName);
- X if (tempnamlen > maxnamlen)
- X {
- X if (fibp->fib_DirEntryType < 0)
- X {
- X maxnamlen = tempnamlen;
- X }
- X else if ((LSFlags & WILDPATH) == 0)
- X maxnamlen = tempnamlen;
- X }
- X
- X /* Allocate another FibEntry, put the info inside */
- X if (FillFibEntry (fibhead, fibp) == 0)
- X goto BADALLOC;
- X }
- X }
- X } while (nextstat != 0);
- X
- X/* No entries found? print message and return FALSE */
- X if ((dircount + filecount) == 0)
- X {
- X if ((LSFlags & NOHEADERS) == 0)
- X {
- X if ((dfcount != 0) || ((LSFlags & WILDPATH) != 0))
- X WSTR("No match.\n");
- X else
- X {
- X LSFlagsX |= EMPTYDIRFLAG;
- X
- X if ((LSFlags & LONGLIST) != 0)
- X WSTR("total 0\n");
- X }
- X }
- X }
- X else
- X {
- X if ((LSFlags & (SHOWDIRS | SHOWFILES)) != 0)
- X {
- X if ((LSFlags & LONGLIST) == 0) /* Short listing wanted */
- X {
- X SListDir (fibhead);
- X gentrycnt++;
- X }
- X else /* Full listing */
- X LListDir (fibhead);
- X
- X if ((dircount + filecount) > 0) gentrycnt++;
- X }
- X }
- END_OF_FILE
- if test 45212 -ne `wc -c <'src/ls.c.aa'`; then
- echo shar: \"'src/ls.c.aa'\" unpacked with wrong size!
- fi
- # end of 'src/ls.c.aa'
- fi
- echo shar: End of archive 4 \(of 4\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
- Mail comments to the moderator at <amiga-request@cs.odu.edu>.
- Post requests for sources, and general discussion to comp.sys.amiga.
-